<?php

declare(strict_types=1);

namespace Zlf\AppValidate\Rule;

use Zlf\Unit\Is;

/**
 * 多选验证器
 */
class MultiSelectorValidate extends RuleAbstract
{
    /**
     * 枚举数据源
     * @var array
     */
    protected $_enums = [];

    /**
     * 是否允许出现其他值
     * @var bool
     */
    protected $_allowOther = false;

    /**
     * 出现其他值时的错误信息
     * @var string
     */
    protected $_allowOtherError = '{label}中含有无效的选项';

    /**
     * 排除无效值，开启后 $_allowOther 将无效
     * @var bool
     */
    protected $_excludeInvalid = true;

    /**
     * 错误提示
     * @var string
     */
    protected $_error = '{label}选择错误';

    /**
     * 是否严格检查类型
     * @var bool
     */
    protected $_strict = false;

    /**
     * 设置枚举数据
     * @param array $enums 枚举数据数组
     * @return $this
     */
    public function setEnums(array $enums): MultiSelectorValidate
    {
        $this->_enums = $enums;
        return $this;
    }

    /**
     * 设置是否严格检查类型
     * @param bool $strict 是否严格检查类型
     * @return $this
     */
    public function setStrict(bool $strict): MultiSelectorValidate
    {
        $this->_strict = $strict;
        return $this;
    }

    /**
     * 设置是否允许其他的选择存在
     * @param bool $allowOther 是否允许其他值
     * @return $this
     */
    public function setAllowOther(bool $allowOther): MultiSelectorValidate
    {
        $this->_allowOther = $allowOther;
        return $this;
    }

    /**
     * 设置允许其他的选择存在的错误信息
     * @param string $allowOtherError 自定义错误信息
     * @return $this
     */
    public function setAllowOtherError(string $allowOtherError): MultiSelectorValidate
    {
        $this->_allowOtherError = $allowOtherError;
        return $this;
    }

    /**
     * 设置是否排除无效值
     * @param bool $excludeInvalid 是否排除无效值
     * @return $this
     */
    public function setExcludeInvalid(bool $excludeInvalid): MultiSelectorValidate
    {
        $this->_excludeInvalid = $excludeInvalid;
        return $this;
    }

    /**
     * 验证枚举
     * @param mixed $value 输入值
     * @param string $label 验证名
     * @return bool 验证结果
     */
    public function validate($value, string $label = ''): bool
    {
        if (Is::list($value)) {
            if (count($value) === 0 && $this->_noSkipping === true) {
                $this->_value = $value;
                return true;
            }
            $_value = [];
            foreach ($value as $val) {
                if (!in_array($val, $this->_enums, $this->_strict)) {
                    if ($this->_excludeInvalid === true) { // 排除无效值
                        continue;
                    }
                    if ($this->_allowOther === false) { // 不允许出现其他值
                        return $this->addError($this->_allowOtherError, $label);
                    }
                }
                $_value[] = $val;
            }
            $this->_value = $_value;
            return true;
        }
        return $this->addError($this->_error, $label);
    }
}
